﻿using Module.FlowChart.Model;
using Module.FlowChart.RunAble.Code;
using Module.FlowChart.RunAble.Code.Runner;
using Module.FlowChart.RunAble.Code.View;
using Module.FlowChart.View;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace Module.FlowChart.RunAble.View
{
    internal class ViewManager_Code : ViewManager_FCBase
    {


        public override string TypeName => RunAbleFCWorkPage.TypeNameS;
        static public Dictionary<string, ViewManager_Code> Mgrs = new Dictionary<string, ViewManager_Code>();
        static public ViewManager_Code CurrentMgr;
        new static Document Document;
        static ViewManagerHandles ViewHandles = null;
        static CodeRunnerX runner;
        static bool IsRunning;
        static IVarShower VarShower;

        public ViewManager_Code(ViewManagerHandles h, Document doc, RunAbleFCWorkPage page, Control container)
           : base(h, doc, page, container)
        {

            if (Document != doc)
            {
                OnDocChanged(Document, doc);
            }
            Document = doc;
            Info.IsRunning = () => { return IsRunning; };
            if (ViewHandles == null)
            {
                ViewHandles = h;
            }
            //************************* 初始化其他参数
            DropDiffer = new Size(0, 0);
            Mgrs.Add(page.Name, this);
        }

        static void OnDocChanged(Document old, Document newdoc)
        {
            if (IsRunning)
            {
                runner?.StopSync();
            }
        }
        #region -----------     Menu    ---------------------------------
        static private ToolStripMenuItem Menu_Run;
        static private ToolStripMenuItem Menu_Run_ToEnd;
        static private ToolStripMenuItem Menu_Run_Step_Ignore;
        static private ToolStripMenuItem Menu_Run_Step_Into;
        static private ToolStripMenuItem Menu_Run_StartStepRun;
        static private ToolStripMenuItem Menu_Run_Stop;
        static private ToolStripMenuItem Menu_SaveAs;
        static private ContextMenuStrip _Menu_NodeRightClick;
        protected override ContextMenuStrip Menu_NodeRightClick { get => _Menu_NodeRightClick; set => _Menu_NodeRightClick = value; }

        protected override void CreatMenu()
        {
            if (Menu_Run != null)
                return;
            Menu_Run = new ToolStripMenuItem();
            Menu_Run_ToEnd = new ToolStripMenuItem();
            Menu_Run_StartStepRun = new ToolStripMenuItem();
            Menu_Run_Step_Ignore = new ToolStripMenuItem();
            Menu_Run_Step_Into = new ToolStripMenuItem();
            Menu_Run_Stop = new ToolStripMenuItem();
            Menu_SaveAs = new ToolStripMenuItem();
            // 
            // Menu_Run
            // 
            Menu_Run.DropDownItems.AddRange(new ToolStripItem[] {
             Menu_Run_ToEnd,
             Menu_Run_StartStepRun,
              Menu_Run_Step_Into,
             Menu_Run_Step_Ignore,
             Menu_Run_Stop});
            Menu_Run.Name = "Menu_Run";
            Menu_Run.Size = new System.Drawing.Size(62, 28);
            Menu_Run.Text = "运行";
            // 
            // Menu_Run_ToEnd
            // 
            Menu_Run_ToEnd.Name = "Menu_Run_ToEnd";
            Menu_Run_ToEnd.Size = new System.Drawing.Size(236, 34);
            Menu_Run_ToEnd.Text = "执行到结束";
            Menu_Run_ToEnd.ShortcutKeys = Keys.F5;
            // 
            // Menu_Run_StartStepRun
            // 
            Menu_Run_StartStepRun.Name = "Menu_Run_StartStepRun";
            Menu_Run_StartStepRun.Size = new System.Drawing.Size(236, 34);
            Menu_Run_StartStepRun.Text = "开始单步执行";
            Menu_Run_StartStepRun.ShortcutKeys = Keys.Control | Keys.F11;
            // 
            // Menu_Run_Step_Ignore
            // 
            Menu_Run_Step_Ignore.Name = "Menu_Run_Step_Ignore";
            Menu_Run_Step_Ignore.Size = new Size(236, 34);
            Menu_Run_Step_Ignore.Text = "单步跳过";
            Menu_Run_Step_Ignore.ShortcutKeys = Keys.F10;
            // 
            // Menu_Run_Step_Into
            // 
            Menu_Run_Step_Into.Name = "Menu_Run_Step_Into";
            Menu_Run_Step_Into.Size = new Size(236, 34);
            Menu_Run_Step_Into.Text = "单步跳入";
            Menu_Run_Step_Into.ShortcutKeys = Keys.F11;
            // 
            // Menu_Run_Stop
            // 
            Menu_Run_Stop.Name = "Menu_Run_Stop";
            Menu_Run_Stop.Size = new System.Drawing.Size(236, 34);
            Menu_Run_Stop.Text = "结束";

            Handles.AddMenu(Menu_Run);

            Menu_SaveAs.Name = "Save";
            Menu_SaveAs.Size = new System.Drawing.Size(236, 34);
            Menu_SaveAs.Text = "保存";
            Handles.AddMenu(Menu_SaveAs);
            Menu_SaveAs.Click += (s, e) =>
            {
                Form_SaveAs.ShowDialog(new Dictionary<string, Action<float>>() {
                    { "PPT",(s)=>SaveAsPPT(s) }
                });
            };
            Menu_SaveAs.Visible = true;


            Menu_Run_StartStepRun.Click += StartStepRun;
            Menu_Run_ToEnd.Click += RunToEnd;
            Menu_Run_Step_Ignore.Click += NextStepIgnore;
            Menu_Run_Step_Into.Click += NextStepInto;
            Menu_Run_Stop.Click += Stop;



            Menu_NodeRightClick = new ContextMenuStrip();
            var m1 = new ToolStripMenuItem("删除");
            m1.Name = "Menu_NodeRightClick_Delete";
            m1.Font = new Font("宋体", 10);
            m1.Click += (s, e) =>
            {
                string msg = CurrentMgr.Info.Page.RemoveNode(CurrentMgr.Info.RightClickNode);
                if (msg != "")
                    MessageBox.Show(msg, "错误");
                else
                {
                    CurrentMgr.SetNeedRedraw();
                    if (CurrentMgr.Info.RightClickNode == CurrentMgr.Info.SelectedNode)
                    {
                        CurrentMgr.Info.SelectedNode = 0;
                        ShowPropertyEditor(null);
                    }
                }
            };
            Menu_NodeRightClick.Items.Add(m1);
            var m2 = new ToolStripMenuItem("删除线段");
            m2.Name = "Menu_NodeRightClick_DeleteLines";
            m2.Font = new Font("宋体", 10);
            m2.Click += (s, e) =>
            {
                string msg = CurrentMgr.Info.Page.RemoveLineOfNode(CurrentMgr.Info.RightClickNode);
                if (msg != "")
                    MessageBox.Show(msg, "错误");
                else
                    CurrentMgr.SetNeedRedraw();
            };
            Menu_NodeRightClick.Items.Add(m2);
            Menu_NodeRightClick.Parent = null;
        }
        protected override void InitMenuState(bool visible)
        {
            if (visible)
            {
                if (Info.IsRunning())
                {
                    Menu_Run.Visible = true;
                    Menu_Run_StartStepRun.Enabled = false;
                    Menu_Run_ToEnd.Enabled = true;
                    Menu_Run_Step_Ignore.Enabled = true;
                    Menu_Run_Step_Into.Enabled = true;
                    Menu_Run_Stop.Enabled = true;
                    Menu_SaveAs.Visible = true;
                }
                else
                {
                    Menu_Run.Visible = true;
                    Menu_Run_StartStepRun.Enabled = true;
                    Menu_Run_ToEnd.Enabled = true;
                    Menu_Run_Step_Ignore.Enabled = false;
                    Menu_Run_Step_Into.Enabled = false;
                    Menu_Run_Stop.Enabled = false;
                    Menu_SaveAs.Visible = true;
                }
            }
            else
            {
                Menu_Run.Visible = false;
                Menu_SaveAs.Visible = false;
            }
        }
        #endregion
        #region -----------     Runner  ---------------------------------

        protected override void InitRunner()
        {
            if (runner != null)
                return;
            RunnerHandles h = new RunnerHandles();
            h.GetNode = (name, id) =>
            {
                var p = ViewHandles.GetDocument().TryGetPage(name);
                if (p == null)
                    throw new Exception("没有找到页：" + name);
                return (p as FCWorkPageBase).FindNode(id);
            };
            h.FindFunction = (name) =>
            {
                var p = ViewHandles.GetDocument().TryGetPage(name);
                if (p == null)
                    throw new Exception("没有找到页：" + name);
                return p.StartNode;
            };
            h.OutPutValue = (f) => { ConsoleManager.Instance.WriteLine("OUT:" + f); };
            h.OnRunNode = (name, index) =>
            {
                Debugger.Assert(index > 0, "index应该大于0");
                ConsoleManager.Instance.WriteLine($"即将运行节点{name}:{index}");
                h.VarShower.UpdateLast();
                Mgrs[name].Info.HighLightNode = index;
                Mgrs[name].Drawer.Refresh();
                if (Mgrs[name] != CurrentMgr)
                {
                    ViewHandles.ChangePage(name);
                }
                h.VarShower.UpdateLast();
            };
            h.TryGetInputValue = () =>
            {
                if (!ConsoleManager.Instance.IsCacheEmpty())
                {
                    return ConsoleManager.Instance.CacheGet();
                }
                Debugger.Check("缓冲区空，无法获取数据");
                return 0;
            };
            h.CanGetInputValue = () => { return !ConsoleManager.Instance.IsCacheEmpty(); };
            h.OnNewFunctionReady = (context) =>
            {
                h.VarShower.Add(context);
            };
            h.OnFunctionReturn = (name, index) =>
            {
                ConsoleManager.Instance.WriteLine($"运行返回{name}");
                Mgrs[name].Info.HighLightNode = index;
                Mgrs[name].Drawer.Refresh();
            };
            h.OnStartRun = () =>
            {
                Menu_Run_StartStepRun.Enabled = false;
                Menu_Run_Step_Into.Enabled = true;
                Menu_Run_Step_Ignore.Enabled = true;
                Menu_Run_Stop.Enabled = true;
                ConsoleManager.Instance.InitAndShow(
                    () => { if (runner.RunState == RunState.WaitForIO) runner.IOInputed(); }
                    , GetConsoleStartPosition(ConsoleManager.Instance.GetConsoleSize()));
                IsRunning = true;
                h.VarShower.Show(CurrentMgr.Info.Page.Name, CurrentMgr.Info.Container);
            };
            h.OnEndRun = () =>
            {
                ConsoleManager.Instance.WriteLine($"一共运行了{runner.StepCount}次");
                Menu_Run_StartStepRun.Enabled = true;
                Menu_Run_Step_Into.Enabled = false;
                Menu_Run_Step_Ignore.Enabled = false;
                Menu_Run_StartStepRun.Enabled = true;
                Menu_Run_ToEnd.Enabled = true;
                Menu_Run_Stop.Enabled = false;
                IsRunning = false;
                h.VarShower.RemoveAll();
                h.VarShower.HideView();
                CurrentMgr.Drawer.Refresh();
            };
            h.CMD = (title, msg) =>
            {
                if (title == "Console")
                {
                    ConsoleManager.Instance.WriteLine(msg); return;
                }
                // MessageBox.Show(title+":"+msg);
            };

            h.VarShower = VarShower = new Form_Vars();

            //runner = new FCRunner(h);
            runner = new CodeRunnerX(h);
        }
        private Point GetConsoleStartPosition(Size consolesize)
        {
            int w = Screen.PrimaryScreen.Bounds.Width;
            int h = Screen.PrimaryScreen.Bounds.Height;
            return new Point(w - consolesize.Width, (int)(0.9f * h) - consolesize.Height);
        }
        #endregion
        #region -----------     Drawer  ---------------------------------
        protected override PageDrawer CreatPageDrawer()
        {
            return new PageDrawer_Code(Info);
        }

        #endregion


        protected override ListViewGroup[] CreatCandidateListGroups()
        {
            string[] itemname = "Asg;IF;IO;End".Split(';');

            ListViewGroup group = new ListViewGroup("基础图形");
            ListViewItem[] items = new ListViewItem[itemname.Length];
            for (int i = 0; i < items.Length; i++)
            {
                ListViewItem lvi = new ListViewItem();

                //lvi.ImageIndex =0;     //通过与imageList绑定，显示imageList中第i项图标
                lvi.Text = itemname[i];
                items[i] = lvi;
                lvi.Group = group;
            }
            return new ListViewGroup[] { group };
        }

        ~ViewManager_Code()
        {
            //SetPageAndContainer(null,null,false);
        }
        public override void DestoryMgr()
        {
            base.DestoryMgr();
            Mgrs.Remove(Info.Page.Name);
        }
        public override void SetActive(bool v)
        {
            base.SetActive(v);
            if (v)
            {
                CurrentMgr = this;
                if (IsRunning)
                {
                    VarShower.Show(Info.Page.Name, Info.Container);
                }
            }
            else
            {
                if (CurrentMgr == this)
                {
                    CurrentMgr = null;
                }
            }
        }
        public override void OnPageNameChanged(string oldname, string newname)
        {
            base.OnPageNameChanged(oldname, newname);
            var mgr = Mgrs[oldname];
            Mgrs.Remove(oldname);
            Mgrs[newname] = mgr;

        }

        #region 控件事件
        protected override void OnDragFromListView(ListViewItem item)
        {
            switch (item.Index)
            {
                case 0:
                    //codenode
                    Info.DragType = FCNodeType.Assign;
                    break;
                case 1:
                    //codenode
                    Info.DragType = FCNodeType.IF; break;
                case 2:
                    //codenode
                    Info.DragType = FCNodeType.IO; break;
                case 3:
                    //codenode
                    Info.DragType = FCNodeType.Terminal; break;
                default:
                    break;
            }
        }
        #endregion

        #region 菜单功能
        /// <summary>
        /// 菜单功能 ：开始单步运行
        /// </summary>
        private void StartStepRun(object sender = null, EventArgs e = null)
        {
            runner.StartSync(RunState.NextInto);
        }
        /// <summary>
        /// 菜单功能：运行下一步
        /// </summary>
        private void NextStepInto(object sender = null, EventArgs e = null)
        {
            runner.NextSync(RunState.NextInto);
        }
        /// <summary>
        /// 菜单功能：运行下一步
        /// </summary>
        private void NextStepIgnore(object sender = null, EventArgs e = null)
        {
            runner.NextSync(RunState.NextIgnore);
        }
        /// <summary>
        /// 菜单功能：运行到结束
        /// </summary>
        private void RunToEnd(object sender = null, EventArgs e = null)
        {
            if (runner.RunState != RunState.NotRunning)
            {//继续执行到开始

                runner.NextSync(RunState.ToEnd);
            }
            else
            {//直接执行到开始
                runner.StartSync(RunState.ToEnd);
            }
        }
        /// <summary>
        /// 菜单功能：结束运行
        /// </summary>
        private void Stop(object sender = null, EventArgs e = null)
        {
            runner.StopSync();
        }

        /// <summary>
        /// 菜单功能：保存为ppt
        /// </summary>
        private void SaveAsPPT(float s)
        {
            string path;
            SaveFileDialog fbd = new SaveFileDialog();
            fbd.Filter = "ppt|*.ppt;*.pptx" + Document.DocExtension;// "Excel|*.xls;*.xlsx;";
            fbd.Title = "保存为";
            var dre = fbd.ShowDialog();
            if (dre == DialogResult.OK)
            {
                path = fbd.FileName;
            }
            else
            {
                return;
            }
            PPTCreater.CreatPPT_Runable(path, new List<FCNode>(CurrentMgr.Info.Page.Nodes.Values), new List<FCLine>(CurrentMgr.Info.Page.Lines.Values), s);
        }
        #endregion
    }
}